﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LoA.Shared.Interfaces;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace LoA.WorldSkyEngine {
	public class WorldSkyComponent : DrawableGameComponent, IWorldSky {
		private static WorldSkyComponent _current = null;
		public static WorldSkyComponent Current { get { return _current; } }

		ICamera Camera;

		public WorldSkyComponent(Game game, ICamera camera)
			: base(game) {
			if (_current == null) {
				_current = this;
			}
			this.Camera = camera;
		}

		string lastTexture;
		TextureMaterial textureMaterial;
		Matrix worldMatrix;
		float rotationY;
		Vector3 position = Vector3.Zero;
		Model skydomeModel;

		//CullMode cullMode;
		//bool depthBufferEnable;
		//bool depthBufferWriteEnable;
		private DepthStencilState depthStencilState;
		private RasterizerState rasterizerState;

		public Vector3 Position { get { return position; } set { position = value; } }

		protected override void LoadContent( ) {
			skydomeModel = this.Game.Content.Load<Model>(@"Model\" + "sky");
			GetTextureMaterial("skyNight", Vector2.One);
		}

		private void GetTextureMaterial(string textureFilename, Vector2 tile) {
			if (lastTexture != textureFilename) {
				lastTexture = textureFilename;
				Texture2D texture = this.Game.Content.Load<Texture2D>(@"Texture\Sky\" + textureFilename);
				textureMaterial = new TextureMaterial(texture, tile);
			}
		}

		private void SetEffectMaterial(BasicEffect basicEffect, Matrix viewMatrix, Matrix projectionMatrix) {
			basicEffect.DiffuseColor = Color.White.ToVector3( );

			// Texture Material 
			basicEffect.Texture = textureMaterial.Texture;
			basicEffect.TextureEnabled = true;

			// Transformation 
			basicEffect.World = worldMatrix;
			basicEffect.View = viewMatrix;
			basicEffect.Projection = projectionMatrix;

			//	Camera.SetLighting(basicEffect);
		}

		private void SaveGraphicsDeviceState( ) {
			rasterizerState = this.GraphicsDevice.RasterizerState;
			depthStencilState = this.GraphicsDevice.DepthStencilState;
		}

		private void RestoreGraphicsDeviceState( ) {
			this.GraphicsDevice.RasterizerState = rasterizerState;
			this.GraphicsDevice.DepthStencilState = depthStencilState;
		}

		public void MoveHorizont(Vector3 position) {
			this.position = position;
		}

		public override void Update(GameTime gameTime) {
			rotationY += (float)gameTime.ElapsedGameTime.TotalSeconds * 0.004f;

			Hour.Add(new TimeSpan(0, 0, 10));

			if (6 <= Camera.DayTime.Hours && Camera.DayTime.Hours < 9)
				GetTextureMaterial("skySunrise", Vector2.One);
			else if (9 <= Camera.DayTime.Hours && Camera.DayTime.Hours < 18)
				GetTextureMaterial("skyDay", Vector2.One);
			else if (17 <= Camera.DayTime.Hours && Camera.DayTime.Hours < 20)
				GetTextureMaterial("skySunset", Vector2.One);
			else
				GetTextureMaterial("skyNight", Vector2.One);

			worldMatrix =
				Matrix.CreateScale(10) *
				//Matrix.CreateRotationX(-MathHelper.PiOver2) * 
				Matrix.CreateRotationY(rotationY) *
				Matrix.CreateTranslation(position.X, position.Y, position.Z);
		}

		public override void Draw(GameTime gameTime) {
			SaveGraphicsDeviceState( );

			//device.RenderState.CullMode = CullMode.CullClockwiseFace;
			this.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
			//device.RenderState.DepthBufferEnable = true;
			//device.RenderState.DepthBufferWriteEnable = true;
			this.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

			foreach (ModelMesh modelMesh in skydomeModel.Meshes) {
				// We are only rendering models with BasicEffect 
				foreach (BasicEffect basicEffect in modelMesh.Effects)
					SetEffectMaterial(basicEffect, Camera.ViewMatrix, Camera.ProjectionMatrix);

				modelMesh.Draw( );
			}

			//device.RenderState.FillMode = FillMode.Solid;
			RestoreGraphicsDeviceState( );

		}

		TimeSpan Hour = new TimeSpan( );
		public void SetLighting(BasicEffect effect) {
			Hour.Add(new TimeSpan(Hour.Hours / 24 * -24, 0, 0));

			int hour = Hour.Hours - 12;
			hour = (int)Math.Pow(-1, Math.Sign(hour)) * hour;
			// Set default lighting
			//effect.EnableDefaultLighting( );
			effect.PreferPerPixelLighting = true;

			// Set the fog to match the black background color
			effect.FogEnabled = true;
			effect.FogColor = Vector3.Zero;
			effect.FogStart = 100;
			effect.FogEnd = 320;
		}

		public void SetLighting(SkinnedEffect effect) {
			// Set default lighting
			//effect.EnableDefaultLighting( );
			effect.PreferPerPixelLighting = true;

			// Set the fog to match the black background color
			effect.FogEnabled = true;
			effect.FogColor = Vector3.Zero;
			effect.FogStart = 100;
			effect.FogEnd = 320;
		}
	}

	public class TextureMaterial {
		Texture2D texture;
		Vector2 uvTile;

		#region Properties
		public Texture2D Texture { get { return texture; } set { texture = value; } }
		public Vector2 UVTile { get { return uvTile; } set { uvTile = value; } }
		#endregion

		public TextureMaterial( ) { }

		public TextureMaterial(Texture2D texture, Vector2 uvTile) {
			this.texture = texture;
			this.uvTile = uvTile;
		}
	}
}